/*
DIP
*/

#ifndef __dip_h__
#define __dip_h__

//#include <agent.h>
//#include <packet.h>
//#include <sys/types.h>
//#include <cmu/list.h>
//#include <scheduler.h>

#include <cmu-trace.h>
#include <priqueue.h>
#include <dip/dip_neighbor.h>
#include <dip/dip_packet.h>
#include <classifier/classifier-port.h>
#include <mobilenode.h>

/*
  Allows DIP to use link-layer (802.11) feedback in determining when
  links are up/down.
*/
#define DIP_LINK_LAYER_DETECTION


class DIP;



/* Various constants used for the expanding ring search */
#define TTL_START     5
#define TTL_THRESHOLD 20
#define TTL_INCREMENT 2

// This should be somewhat related to arp timeout
#define NODE_TRAVERSAL_TIME     0.03             // 30 ms
#define packetSize  512

// Should be set by the user using best guess (conservative)
#define NETWORK_DIAMETER        30             // 30 hops

// Must be larger than the time difference between a node propagates a route
// request and gets the route reply back.

//#define RREP_WAIT_TIME     (3 * NODE_TRAVERSAL_TIME * NETWORK_DIAMETER) // ms
//#define RREP_WAIT_TIME     (2 * REV_ROUTE_LIFE)  // seconds
#define RREP_WAIT_TIME         1.0  // sec

#define ID_NOT_FOUND    0x00
#define ID_FOUND        0x01
//#define INFINITY        0xff

// The followings are used for the forward() function. Controls pacing.
#define DELAY 1.0           // random delay
#define NO_DELAY -1.0       // no delay

// think it should be 30 ms
#define ARP_DELAY 0.01      // fixed delay to keep arp happy

#define PREDIC_INTERVAL         10               //predictability
#define HELLO_INTERVAL          3               // 1000 ms
#define ALLOWED_HELLO_LOSS      3               // packets
#define BAD_LINK_LIFETIME       3               // 3000 ms
#define MaxHelloInterval        (1.25 * HELLO_INTERVAL)
#define MinHelloInterval        (0.75 * HELLO_INTERVAL)
#define PREDIC                  0.5
#define alpha                   0.4
/*
  Timers (Broadcast ID, Hello, Neighbor Cache, Route Cache)
*/
class PredicTimer : public Handler {
public:
        PredicTimer(DIP* a) : agent(a) {}
        void	handle(Event*);
private:
        DIP    *agent;
	Event	intr;
};

class DIPHelloTimer : public Handler {
public:
        DIPHelloTimer(DIP* a) : agent(a) {}
        void	handle(Event*);
private:
        DIP    *agent;
	Event	intr;
};

class DIPNeighborTimer : public Handler {
public:
        DIPNeighborTimer(DIP* a) : agent(a) {}
        void	handle(Event*);
private:
        DIP    *agent;
	Event	intr;
};

/*
  The Routing Agent
*/
class DIP: public Agent {

  /*
   * make some friends first
   */


        friend class PredicTimer;
        friend class DIPHelloTimer;
        friend class DIPNeighborTimer;
        friend class dip_rqueue;
        //friend class RouteCacheTimer;
        //friend class LocalRepairTimer;

 public:
        DIP(nsaddr_t id);

        void		recv(Packet *p, Handler *);

 protected:
        int             command(int, const char *const *);
        int             initialized() { return 1 && target_; }

        /*
         * Route Table Management
         */
        void            rt_resolve(Packet *p);
        DIP_Neighbor*   GetUtility(Packet *p);
 public:
        void            rt_ll_failed(Packet *p);
        //void            handle_link_failure(nsaddr_t id);
        double          GetDisbyID(nsaddr_t a,nsaddr_t b);
        MobileNode*     GetNode(nsaddr_t id);
 protected:
        //void            rt_purge(void);



        /*
         * Predictability Management
         */
        void predic_update();
        void retry();


       /*
         * Neighbor Management
         */
        void            nb_insert(nsaddr_t id);
        DIP_Neighbor*       nb_lookup(nsaddr_t id);
        void            nb_delete(nsaddr_t id);
        void            nb_purge(void);


        /*
         * Packet TX Routines
         */
        void            forward(nsaddr_t nexthop, Packet *p, double delay);
        void            sendHello(void);
        /*void            sendRequest(nsaddr_t dst);

        void            sendReply(nsaddr_t ipdst, u_int32_t hop_count,
                                  nsaddr_t rpdst, u_int32_t rpseq,
                                  u_int32_t lifetime, double timestamp);*/
        void            sendError(Packet *p, bool jitter = true);

        /*
         * Packet RX Routines
         */
        void            recvDIP(Packet *p);
        void            recvHello(Packet *p);
        //void            recvRequest(Packet *p);
        //void            recvReply(Packet *p);
        void            recvError(Packet *p);

	/*
	 * History management
	 */

	//double 		PerHopTime(dip_rt_entry *rt);


        nsaddr_t        index;                  // IP Address of this node
        //u_int32_t       seqno;                  // Sequence Number
        //int             bid;                    // Broadcast ID


        dip_ncache         nbhead;                 // Neighbor Cache
        //dip_ucache          nuhead;                 // Neighbor utility Cache

        /*
         * Timers
         */
        PredicTimer  btimer;
        DIPHelloTimer      htimer;
        DIPNeighborTimer   ntimer;
        //RouteCacheTimer rtimer;
        //LocalRepairTimer lrtimer;


        /*
         *  A "drop-front" queue used by the routing layer to buffer
         *  packets to which it does not have a route.
         */
        dip_rqueue         rqueue;

        /*
         * A mechanism for logging the contents of the routing
         * table.
         */
        Trace           *logtarget;

        /*
         * A pointer to the network interface queue that sits
         * between the "classifier" and the "link layer".
         */
        PriQueue        *ifqueue;

        /*
         * Logging stuff
         */
        void            log_link_del(nsaddr_t dst);
        void            log_link_broke(Packet *p);
        void            log_link_kept(nsaddr_t dst);

	/* for passing packets up to agents */
	PortClassifier *dmux_;

};

#endif /* __dip_h__ */
